home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / V11N10.ARJ / SPRINT.ASM < prev    next >
Assembly Source File  |  1992-03-09  |  25KB  |  747 lines

  1.         page    64,132
  2. ;========================================================================
  3. ;                            SPRINTER 
  4. ;                      Cursor Speedup Program
  5. ;                   Written 1992 by Douglas Boling
  6. ;========================================================================
  7. ;========================================================================
  8. ; BIOS_DATA segment
  9. ;========================================================================
  10. bios_data    segment at 40h
  11.  
  12.         org    17h
  13. bios_shift_stat db    ?            ;Shift status of keyboard
  14.         org    1ah
  15. keybuff_head    dw    ?            ;Pointer to first entry in
  16.         org    1ch                     ;  BIOS keyboard buffer.
  17. keybuff_tail    dw    ?                       ;Pointer to last entry in
  18.         org    80h                     ;  BIOS keyboard buffer.
  19. keybuff_start    dw    ?                       ;Pointer to beginning of
  20.         org    82h                     ;  BIOS keyboard buffer.
  21. keybuff_end     dw    ?                       ;Pointer to end of BIOS
  22.         org    96h                     ;  keyboard buffer.
  23. kb_status    db    ?            ;Status of keyboard
  24. bios_data    ends
  25.  
  26. ;========================================================================
  27. ; Code segment (code and data)
  28. ;========================================================================
  29. code        segment para public'code'
  30.         assume    cs:code
  31.  
  32.         org    2ch
  33. env_seg         dw    ?            ;Pointer to environment seg
  34.         org    80h
  35. command_tail    db    ?
  36.         org    100h
  37. begin:        jmp    initialize
  38.  
  39. program        db    13,10,"Sprinter 1.0 "
  40. copyright    db    "Copyright (c) 1992 Douglas Boling",13,10
  41.         db    "First published in PC Magazine, May 26, 1992",13,10
  42.               db    "For help type: sprinter /?",13,10
  43.          db    13,10,"$",1Ah
  44.  
  45. ;------------------------------------------------------------------------
  46. ; Memory locations required for program.
  47. ;------------------------------------------------------------------------
  48. enable_flag    db    1            ;1 = enabled, 0 = disabled
  49. shift_status    db    0            ;bits represent shift status
  50. last_code    db    0            ;Previous scan code
  51. cursor_code    dw    0            ;Cursor code currently active
  52. shift_mask    db    11h            ;Activate using Alt keys
  53. make_kept    db    0            ;key not passed to BIOS
  54. key_count    db    2            ;Number of keys pushed/int
  55.  
  56. scanlist_ptr    label   dword            ;Pointer to list of scan codes
  57.         dw    offset scanlist        ;Offset
  58.         dw    ?            ;Segment
  59. scanlist    db    48h,4bh,4dh,50h,49h,51h    ;Cursor key scancodes
  60. shiftlist    db    38h,1dh,2ah,36h        ;Alt, Ctl, and L/R shift codes
  61. scanlist_end    =    $
  62.  
  63. environment_flg    db    1            ;1 = environment still owned
  64. int8h        dd    ?            ;int 8h vector  (Timer)
  65. int9h        dd    ?            ;int 9h vector  (Keyboard)
  66.  
  67. ;========================================================================
  68. ; TIMERINT receives control when an interrupt 8 is generated.
  69. ;========================================================================
  70. timerint        proc    far
  71.          assume    cs:code,ds:nothing,es:nothing
  72.          pushf
  73.          call    cs:[int8h]        ;Go to BIOS routine
  74.         cmp    cs:enable_flag,0    ;See if program enabled
  75.          je    timer_exit1        ;No, exit
  76.         push    ax
  77.         mov    al,cs:shift_status    ;See if shift combination
  78.         mov    ah,cs:shift_mask
  79.         test    al,ah
  80.         je     timer_exit              ;No, exit
  81.         not    ah            ;See if any other shift key
  82.         and     al,ah                 ;  is active.
  83.  
  84.         mov    ax,cs:cursor_code       ;Get saved cursor key code
  85.         or    ax,ax                   ;See if cursor key active
  86.         je    timer_exit        ;No, exit
  87. ;------------------------------------------------------------------------
  88. ;If shift combination set and cursor key pressed, put scancode into buffer.
  89. ;------------------------------------------------------------------------
  90.         push    ds                      ;Yes, Save registers needed
  91.         push    bx                      ;  for keyboard buffer work.
  92.         push    cx
  93.         push    di
  94.         mov    bx,40h            ;DS = BIOS data segment
  95.         mov    ds,bx
  96.         assume    ds:bios_data
  97.         cli                ;No ints when loading buffer
  98.         mov    bx,keybuff_tail        ;Get pointer to end of buffer
  99.         mov    di,bx                 ;Copy to see if buffer full
  100.         xor    ch,ch
  101.         mov    cl,cs:key_count        ;Get num of keys to push
  102. timer0:
  103.         call    advance_keyptr        ;Check ahead in buffer.
  104.         jc    timer1          ;If full, goto end
  105.         mov    [bx],ax            ;Put character in queue
  106.         mov     bx,di            ;Update pointer
  107.         loop    timer0
  108. timer1:
  109.         mov    keybuff_tail,bx        ;Save updated keyboard ptr
  110.         sti                ;Allow interrupts
  111.         pop    di                      ;Restore registers
  112.         pop    cx
  113.         pop    bx
  114.         pop    ds
  115. timer_exit:
  116.         pop    ax
  117. timer_exit1:
  118.          iret                 ;Return
  119. timerint        endp
  120.  
  121. ;========================================================================
  122. ; KEYBINT receives control when an interrupt 9 is generated.
  123. ;========================================================================
  124. keybint         proc    far
  125.         assume    cs:code,ds:nothing,es:nothing
  126.         push    ax
  127.          cmp    cs:enable_flag,0    ;See if enabled. If not jump
  128.          je    go_kb_int1        ;  directly to BIOS.
  129.         in     al,64h               ;Read keyboard status port.
  130.         test    al,1            ;See if output buffer full.
  131.         je    go_kb_int1         ;No, must be some other I/O.
  132.         push    cx
  133.         push    di
  134.         push    ds
  135.         mov    ax,cs
  136.         mov    ds,ax            ;DS = CS
  137.         assume    ds:code
  138.         in     al,60h               ;Read keyboard data port.
  139.         sti                 ;Enable interrupts
  140. ;------------------------------------------------------------------------
  141. ;Compare scan code with list of keys.
  142. ;------------------------------------------------------------------------
  143.         push    es
  144.         les    di,scanlist_ptr        ;Point to list of scan codes.
  145.         mov    cx,offset scanlist_end - offset scanlist
  146.         mov    ah,al            ;Copy scan code
  147.         and    al,7fh            ;Remove break bit from code
  148.         cld
  149.         repne    scasb            ;Scan list
  150.         pop    es
  151.         jne    go_kb_int           ;Scancode not in list go BIOS
  152.         sub    cx,offset scanlist_end - offset scanlist
  153.         neg    cx            ;Make positive
  154.         sub    cl,offset shiftlist - offset scanlist + 1
  155.         jb     cursorkey_found        ;If first 6 codes, cursor code
  156. ;------------------------------------------------------------------------
  157. ;Shift key scancode.  Set or clear bit in shift status.
  158. ;------------------------------------------------------------------------
  159.         cmp    last_code,0e0h        ;See if extended code
  160.         jne    shiftkey1               ;If extended, increase shift
  161.         add    cl,4            ;  for right alt or ctl keys.
  162. shiftkey1:
  163.         mov    al,1            ;Use al as a bit set register
  164.         shl    al,cl            ;Shift bit by index into list
  165.         test    ah,80h            ;See if make or break code
  166.         jne    shiftkey_break        ;Break, jump.
  167.         or    shift_status,al        ;Make, set bit in shift status
  168.         jmp    short go_kb_chk        ;Goto BIOS
  169. shiftkey_break:
  170.         push    ax
  171.         not    al            ;Invert mask to clear bit
  172.         and    shift_status,al        ;Clear bit
  173.         pop    ax
  174. ;------------------------------------------------------------------------
  175. ;If proper accelerator shift key, don't pass key to BIOS
  176. ;------------------------------------------------------------------------
  177. go_kb_chk:
  178.         test    al,shift_mask        ;If this is the proper 
  179.         je    go_kb_int        ;  shift and a cursor key
  180.         cmp    cursor_code,0        ;  is down, don't pass scan
  181.         je    go_kb_int        ;  code to BIOS.
  182.         test    ah,80h            ;See if make or break
  183.         jne    go_kb_chk1
  184.         mov    make_kept,1        ;Indicate make code kept
  185.  
  186.         jmp    short go_kb_int
  187.  
  188.         jmp    short keyb_iret
  189. go_kb_chk1:
  190.         mov    make_kept,0        ;Clear flag.
  191. ;------------------------------------------------------------------------
  192. ;Exit to BIOS keyboard interrupt routine.
  193. ;------------------------------------------------------------------------
  194. go_kb_int:
  195.         mov    last_code,ah        ;Save current code
  196.          pop    ds            ;Restore registers
  197.         pop    di
  198.         pop    cx
  199. go_kb_int1:
  200.         pop    ax
  201.         jmp     cs:[int9h]        ;Go to BIOS routine
  202. ;------------------------------------------------------------------------
  203. ;Discard key. Reset the keyboard and signal end-of-interrupt to the 8259
  204. ;------------------------------------------------------------------------
  205. keyb_iret:
  206.         call    reset_keyboard        ;Reset keyboard
  207.         mov    last_code,ah        ;Save current code
  208.          pop    ds            ;Restore registers
  209.         pop    di
  210.         pop    cx
  211.         pop    ax
  212.                 iret                         ;Return to program
  213. ;------------------------------------------------------------------------
  214. ;Cursor key scancode, check for extended key or number key and numlock on.
  215. ;------------------------------------------------------------------------
  216. cursorkey_found:
  217.         xor    al,al            ;Assume 0 extended scancode
  218.         cmp     last_code,0e0h        ;See if extended key
  219.         jne    cursorkey_numpad
  220.         mov    al,0e0h            ;Load extended keycode.
  221.         jmp    short cursorkey1
  222. cursorkey_numpad:
  223.         push    es
  224.         push    ax
  225.         mov    ax,40h            ;ES = BIOS data segment
  226.         mov    es,ax
  227.         assume    es:bios_data
  228.         pop    ax
  229.         test    es:bios_shift_stat,20h    ;See if numlock active
  230.         pop    es
  231.         assume    es:nothing
  232.         jne    go_kb_int        ;If so, not a cursor key.
  233. ;------------------------------------------------------------------------
  234. ;Check for break code. If break, clear stored scan code.
  235. ;------------------------------------------------------------------------
  236. cursorkey1:
  237.         test    ah,80h            ;See if break
  238.         je     cursorkey_make        ;No, continue
  239.         xor    ax,ax            ;Yes, clear last code
  240. cursorkey_make:
  241.         mov    cursor_code,ax        ;Save cursor code
  242.  
  243.         mov    al,shift_status        ;See if shift combination
  244.         test    shift_mask,al
  245.         jne     keyb_iret
  246.  
  247.         jmp    go_kb_int               ;Yes, goto BIOS
  248. keybint         endp
  249.  
  250. ;========================================================================
  251. ; ADVANCE KEYPTR moves the keyboard buffer pointer to the next free 
  252. ;   location in the BIOS keyboard buffer. 
  253. ; Entry: DI - keyboard head pointer
  254. ; Exit:  CF - Set if keyboard buffer full
  255. ;========================================================================
  256. advance_keyptr    proc    near
  257.         assume    cs:code,ds:bios_data
  258.         inc    di            ;Point to next entry
  259.         inc    di
  260.         cmp    di,keybuff_end      ;See if at the end of the
  261.         jne    advance1        ;  buffer. If so, reset the
  262.         mov    di,keybuff_start    ;  pointer to the start.
  263. advance1:
  264.         cmp    di,keybuff_head     ;See if the buffer is full
  265.         je     advance_full
  266.         clc
  267.         jmp    short advance_exit
  268. advance_full:
  269.         stc
  270. advance_exit:
  271.         ret
  272. advance_keyptr    endp
  273.  
  274. ;========================================================================
  275. ; RESET KEYBOARD resets the interrupts controller.  Used when discarding
  276. ;   scan codes.
  277. ;========================================================================
  278. reset_keyboard    proc    near
  279.         push    ax
  280.                 cli                             ;Disable interrupts
  281.                 in      al,61h                  ;Reset the keyboard
  282.                 mov     ah,al                   ;  controller
  283.                 or      al,80h
  284.                 out     61h,al
  285.                 mov     al,ah
  286.                 out     61h,al
  287.  
  288.                 mov     al,20h                  ;Signal end-of-interrupt to
  289.                 out     20h,al                  ;  the interrupt controller
  290.                 sti                             ;Enable interrupts
  291.         pop    ax
  292.         ret
  293. reset_keyboard    endp
  294. end_of_code    =     $
  295. ;========================================================================
  296. ; End of nonresident code.
  297. ;========================================================================
  298. infomsg1    db    "The available commands are:"
  299.         db    13,10,"/e  Enable acceleration"
  300.         db    13,10,"/d  Disable acceleration"
  301.         db    13,10,"/u  Uninstall program"
  302.         db    13,10,"/s x Set acceleration speed where x"
  303.         db    " is between 1 and 9"
  304.         db    13,10,"/k xx Set shift key where xx is one of"
  305.         db    " the following:"
  306.         db    13,10,"  a  Alt key"
  307.         db    13,10,"  c  Ctl key"
  308.         db    13,10,"  s  Shift key"
  309.         db    13,10,"  lx to specify only the left key"
  310.         db    13,10,"  rx to specify only the right key"
  311.         db    13,10,"/?  Print this message$"
  312. infomsg2    db    "Sprinter removed$"
  313. infomsg3    db    "Sprinter installed",13,10,"$"
  314. infomsg4    db    "Acceleration key is "
  315. keytag        db    15 dup (" "),13,10
  316.         db    "Acceleration speed is "
  317. speedtag    db    2 dup (" "),13,10,10,"$"
  318. errmsg1        db    "Bad commmand$"
  319. errmsg2        db    "Can't remove$"
  320. errmsg3        db    "Bad shift key$"
  321. errmsg4        db    "Not installed$"
  322. errmsg5        db    "Bad key speed$"
  323. end_msg        db    13,10,"$"
  324.  
  325. left_tag    db    "<Left>",0
  326. right_tag    db    "<Right>",0
  327. alt_tag        db    "<Alt>",0
  328. ctrl_tag    db    "<Ctrl>",0
  329. shift_tag    db    "<Shift>",0
  330.  
  331. commands    db    'edksu?'        ;Letters corrsponding to the
  332. commands_end    =    $            ;  command line switches.
  333.  
  334. jumptable:
  335.         dw    offset enable       ;Command routine jump table
  336.         dw    offset disable
  337.         dw    offset keyset
  338.         dw    offset speedset
  339.         dw    offset uninstall
  340.         dw    offset display_help
  341.  
  342. shiftkeys    db    'lracs'            ;Letters corrsponding to the
  343. shiftkeys_end    =    $            ;  shift keys allowed.
  344.  
  345. other_seg    dw    0            ;Segment of installed code
  346. alrdy_installed    db    0            ;bcopy already installed flag
  347. remove_flag    db    0            ;1 = uninstall
  348.  
  349. ;========================================================================
  350. ; INITIALIZE
  351. ;========================================================================
  352. initialize    proc    near
  353.         assume cs:code, ds:code
  354.               cld                ;clear DF
  355.         mov    ah,9            ;display copyright message
  356.         mov    dx,offset program
  357.         int    21h
  358. ;------------------------------------------------------------------------
  359. ;See if a copy is already resident in memory.
  360. ;------------------------------------------------------------------------
  361.         mov    word ptr [begin],0    ;initialize fingerprint
  362.         mov    bx,0a000h        ;Start at UMBs
  363.         mov    ax,cs            ;keep CS value in AX
  364. find_copy:
  365.         inc    bx            ;increment search segment value
  366.         mov    es,bx
  367.         cmp    ax,bx            ;not installed if current
  368.         je    find_copy1            ;  segment is looped back to
  369.         mov    si,offset begin        ;search this segment for ASCII
  370.         mov    di,si            ;  fingerprint
  371.         mov    cx,16
  372.         repe    cmpsb
  373.         jne    find_copy        ;loop back if not found
  374.         inc    alrdy_installed        ;Clear installed flag
  375. find_copy1:
  376.         mov    other_seg,es        ;save installed code segment
  377.         push    cs            ;ES = CS
  378.         pop    es
  379.         assume    es:code
  380. ;------------------------------------------------------------------------
  381. ;Parse the command line for switches.
  382. ;------------------------------------------------------------------------
  383.               mov    si,offset command_tail    ;point SI to command line text
  384.         xor    cx,cx            ;Clear high byte of CX
  385.         add    cl,[si]            ;Get length of command line.
  386.         jz    parse_line_end         ;If zero, skip parse routine
  387.         inc    si
  388. parse_line_loop:
  389.         lodsb                ;Get byte
  390.         cmp    al,'/'            ;Look for command switch
  391.         je     parse_line_skip          ;If found, process command
  392.         loop    parse_line_loop        ;If not, keep looking
  393.         jmp    short parse_line_end
  394. parse_line_skip:
  395.         lodsb                ;Get command
  396.         or     al,20h            ;Convert to lower case
  397.         push    cx
  398.         mov    di,offset commands    ;Point to command letters
  399.         mov    cx,offset commands_end - offset commands
  400.         mov    bx,cx            ;Save number of routines
  401.         repne    scasb            ;Find command letter
  402.         je    command_found
  403.         add    sp,2            ;Clean up stack
  404.         mov    dx,offset errmsg1    ;Command not found msg
  405.         jmp    short disp_error
  406. command_found:
  407.         sub    bx,cx            ;Compute offset into table
  408.         pop    cx            ;Get back character count
  409.         dec    bx
  410.         shl    bx,1            ;Convert to word
  411.         push    es
  412.         call    [bx+offset jumptable]
  413.         pop    es
  414.         jc    disp_error        ;Error if carry set.
  415.         loop    parse_line_loop
  416. parse_line_end:
  417. ;------------------------------------------------------------------------
  418. ;Construct and print Accel key message
  419. ;------------------------------------------------------------------------
  420.         mov    di,offset keytag
  421.         mov    es,other_seg
  422.         mov    al,es:shift_mask    ;Get shift key
  423.         mov    ah,es:key_count        ;Get key speed 
  424.         push    ax            ;Save key speed value
  425.         push    cs
  426.         pop    es
  427.         mov    bl,al            ;See if specific to left
  428.         mov    cl,4            ;  or right keys.
  429.         shr    bl,cl
  430.         test    al,8
  431.         je    accel_0
  432.         or    bl,4
  433. accel_0:
  434.         and    al,07h
  435.         cmp    al,bl            ;Compare left and right 
  436.         je    accel_2            ; masks.
  437.         mov    si,offset left_tag
  438.         ja    accel_1
  439.         mov    si,offset right_tag
  440. accel_1:
  441.         call    copy_str        ;Copy Left/Right tag                
  442. accel_2:
  443.         or    al,bl
  444.         mov    si,offset alt_tag
  445.         test    al,1
  446.         jne    accel_3
  447.         mov    si,offset ctrl_tag
  448.         test    al,2
  449.         jne    accel_3
  450.         mov    si,offset shift_tag
  451. accel_3:
  452.         call    copy_str
  453.         pop    ax            ;Insert key speed value in
  454.         add    ah,30h            ; message
  455.         mov    speedtag,ah
  456.  
  457.         mov    ah,9            ;Print message
  458.         mov    dx,offset infomsg4
  459.         int    21h
  460.  
  461. ;------------------------------------------------------------------------
  462. ;See if installed. If not, install.
  463. ;------------------------------------------------------------------------
  464.         cmp    alrdy_installed,0    ;If not installed, install
  465.         je    install
  466.         mov    ax,4c00h        ;Else, terminate with RC = 0.
  467.         int    21h
  468.  
  469. ;------------------------------------------------------------------------
  470. ;Display error message and exit with Return Code = 1.
  471. ;------------------------------------------------------------------------
  472. disp_error:
  473.         mov    ah,9            ;Print string
  474.         int    21h
  475.         mov    dx,offset end_msg
  476.         mov    ah,9            ;Print CR,LF
  477.         int    21h
  478.         mov    ax,4c01h        ;Exit RC = 1
  479.         int    21h
  480.  
  481. ;------------------------------------------------------------------------
  482. ;Install. Revector interrupts, Terminate and Stay Resident.
  483. ;------------------------------------------------------------------------
  484. install:
  485.         mov    ax,cs            ;Copy code segment
  486.         mov    word ptr [scanlist_ptr+2],ax    ;Load segment into ptr
  487.         mov    ax,3508h        ;Set interrupt 8 (timer)
  488.         int    21h            ;  to the internal handler.
  489.         mov    word ptr [int8h],bx
  490.         mov    word ptr [int8h+2],es
  491.         mov    ax,2508h
  492.         mov    dx,offset timerint
  493.         int    21h
  494.         mov    ax,3509h        ;Set interrupt 9 (keyboard)
  495.         int    21h            ;  to the internal handler.
  496.         mov    word ptr [int9h],bx
  497.         mov    word ptr [int9h+2],es
  498.         mov    ax,2509h
  499.         mov    dx,offset keybint
  500.         int    21h
  501.         mov    dx,offset infomsg3    ;Say program installed.
  502.         mov    ah,9h
  503.         int    21h
  504.         mov    dx,offset end_of_code    ;Get pointer to the end of
  505.         add    dx,15            ;  code.
  506.         mov    cl,4
  507.         shr    dx,cl                   ;Convert to paragraphs
  508.         mov    ax,3100h        ;terminate with ERRORLEVEL = 0
  509.         int    21h            ;Return to DOS.
  510. initialize    endp
  511.  
  512. ;------------------------------------------------------------------------
  513. ; ENABLE activates the cursor speedup feature.
  514. ;------------------------------------------------------------------------
  515. enable      proc    near
  516.         assume    cs:code,ds:code
  517.         mov    es,other_seg        ;point to installed segment
  518.         mov    es:enable_flag,1    ;Set enable flag
  519.         clc
  520.         ret
  521. enable      endp
  522.  
  523. ;------------------------------------------------------------------------
  524. ; DISABLE deactivates the cursor speedup feature.
  525. ;------------------------------------------------------------------------
  526. disable           proc    near
  527.         assume    cs:code,ds:code
  528.         mov    es,other_seg        ;point to installed segment
  529.         mov    es:enable_flag,0    ;Clear enable flag
  530.         clc
  531.         ret
  532. disable           endp
  533.  
  534. ;------------------------------------------------------------------------
  535. ; SPEEDSET sets the number of keys pushed into the buffer per timer int
  536. ;------------------------------------------------------------------------
  537. speedset          proc    near
  538.         assume    cs:code,ds:code
  539. speedset_loop:
  540.         jcxz    speedset_err        ;If EOL, error.
  541.         lodsb
  542.         dec    cx
  543.         cmp    al," "
  544.         jbe    speedset_loop
  545.         sub    al,30h            ;Convert to hex
  546.         jbe    speedset_err
  547.         cmp    al,9
  548.         ja    speedset_err
  549.         mov    es,other_seg           ;Get seg of installed code
  550.         mov    es:key_count,al        ;Set count
  551.         clc
  552. speedset_exit:
  553.         ret
  554. speedset_err:
  555.         mov    dx,offset errmsg5    ;Bad key speed message
  556.         stc
  557.         jmp    short speedset_exit
  558. speedset          endp
  559.  
  560. ;------------------------------------------------------------------------
  561. ; KEYSET sets the shift key for acceleration of the cursor.
  562. ;------------------------------------------------------------------------
  563. keyset           proc    near
  564.         assume    cs:code,ds:code
  565.         mov    dx,003fh        ;Use DX as shift bit mask
  566. keyset_loop:
  567.         mov      al,[si]            ;Get byte
  568.         cmp    al,'/'            ;If next switch, end.
  569.         je     keyset_end
  570.         inc    si
  571.         cmp    al,' '            ;Check for a space.
  572.         jb      keyset_end        ;If non character, exit
  573.         ja      keyset0            ;If not a space, process.
  574.         loop    keyset_loop             ;If at the end of the command
  575.         jmp    short keyset5       ;  line, end.
  576. keyset0:
  577.         or     al,20h            ;Convert to lower case
  578.         mov    di,offset shiftkeys    ;Point to command letters
  579.         push    cx            ;Save command line count
  580.         mov    cx,offset shiftkeys_end - offset shiftkeys
  581.         mov    bx,cx            ;Save number of keys
  582.         repne    scasb            ;Find shift key letter
  583.         je    shiftkey_found        ;If found, continue.
  584.         add    sp,2            ;If not, Clean up stack.
  585.         mov    dx,offset errmsg3    ;Not a proper shift key msg
  586.         stc                ;Set carry and exit.
  587.         jmp    short keyset_exit
  588. shiftkey_found:
  589.         sub    bx,cx            ;Create index into keylist
  590.         dec    bx            ;Check for left and right
  591.         cmp    bl,1            ;qualifiers, if so fix mask.
  592.         ja    keyset2            ;Not left or right, continue
  593.         jb    keyset1            ;Check for left qualifier
  594.         and    dl,38h            ;Right qualifier, Clear off
  595.         jmp    short keyset4        ;  left shift bits.
  596. keyset1:
  597.         and    dl,07h            ;Left qualifier, Clear off
  598.         jmp    short keyset4           ;  right shift bits.
  599. keyset2:
  600.         mov    cl,bl            ;Shift bits by the index into
  601.         sub    cl,2            ;  list of keys. This creates
  602.         mov    bl,11h            ;  a mask compatible with the
  603.         shl    bl,cl            ;  shift mask used in the int
  604.         cmp    bl,44h            ;  routine.
  605.         jne    keyset3                 ;Fix mask if shift key
  606.         mov    bl,0ch
  607. keyset3:
  608.         and    bl,dl            ;Clear off bits for L/R
  609.         or    dh,bl            ;Add to shift mask
  610.         mov    dl,3fh            ;Reset left/right mask
  611. keyset4:
  612.         pop    cx                ;Restore command line counter
  613.         loop    keyset_loop        ;Loop if not EOL
  614. keyset5:
  615.         inc    cx                  ;Fool loop instruction on ret
  616. keyset_end:
  617.         or    dh,dh            ;Check for nul shift mask
  618.         jne    keyset6            ;If zero, set unshiftable bit
  619.         mov    dh,80h            ;  to disable.
  620. keyset6:
  621.         mov    es,other_seg        ;point to installed segment
  622.         mov    es:shift_mask,dh    ;Set new shift mask
  623.         clc
  624. keyset_exit:
  625.         ret
  626. keyset            endp
  627.  
  628. ;------------------------------------------------------------------------
  629. ; DISPLAY HELP prints help message without installing.
  630. ;------------------------------------------------------------------------
  631. display_help     proc    near
  632.         mov    dx,offset infomsg1    ;point to help text.
  633.         stc                ;Set flag to print message.
  634.         ret
  635. display_help     endp
  636.  
  637. ;------------------------------------------------------------------------
  638. ; UNINSTALL deallocates the memory block ownded by the program and 
  639. ; restores the interrupt vectors displaced on installation.
  640. ;------------------------------------------------------------------------
  641. uninstall    proc    near
  642.         assume    cs:code,ds:code
  643.         push    cx            ;Save command line count
  644.         cmp    alrdy_installed,0    ;If not installed, don't
  645.         jne    uninstall0        ;  remove.
  646.         mov    dx,offset errmsg4    ;Not installed msg
  647.         jmp    short uninstall_exit
  648. uninstall0:
  649.         mov    cx,other_seg        ;Get segment of installed prog
  650. ;
  651. ;Make sure the timer and keyboard vectors has not been altered.
  652. ;
  653.         mov    ax,3508h        ;check interrupt 8h vector
  654.         int    21h
  655.         mov    ax,es
  656.         cmp    cx,ax            ;transfer segment to AX
  657.         jne    uninstall_error
  658.         mov    ax,3509h        ;check interrupt 9h vector
  659.         int    21h
  660.         mov    ax,es
  661.         cmp    cx,ax            ;transfer segment to AX
  662.         jne    uninstall_error
  663. ;
  664. ;Restore interrupt 8 and 9 vectors.
  665. ;
  666.         mov    es,cx            ;Copy installed segment
  667.         push    ds            ;save DS
  668.         assume     ds:nothing
  669.         lds    dx,es:[int8h]
  670.         mov    ax,2508h        ;restore interrupt 8h vector
  671.         int    21h
  672.         lds    dx,es:[int9h]
  673.         mov    ax,2509h        ;restore interrupt 9h vector
  674.         int    21h
  675.         pop    ds            ;restore DS
  676.         assume     ds:code
  677. ;
  678. ;Release the memory occupied by the program.
  679. ;
  680.         mov    ah,49h            ;Free memory given to
  681.         int    21h            ;  original program block
  682.         jc    uninstall_error        ;jmp if error
  683.         cmp    es:environment_flg,0    ;See if environment still
  684.         je    uninstall1        ;  owned by resident code.
  685.         push    es
  686.         mov    es,es:env_seg        ;Get segment of environment
  687.         mov    ah,49h            ;Deallocate environment seg
  688.         int    21h
  689.         pop    es
  690.         jc    uninstall_error        ;Jmp if error
  691. uninstall1:
  692. ;
  693. ;Destroy the ASCII fingerprint that identifies the code and exit.
  694. ;
  695.         not    word ptr es:[begin]    ;destroy fingerprint
  696.         mov    dx,offset infomsg2    ;Say program removed.
  697. uninstall_exit:
  698.         stc                ;Set flag to end program
  699.         pop    cx
  700.         ret                ;exit
  701. ;
  702. ;The program can't be uninstalled.  Point to error message and exit.
  703. ;
  704. uninstall_error:
  705.         mov    dx,offset errmsg2    ;Remove error message
  706.         jmp    short uninstall_exit
  707. uninstall    endp
  708.  
  709. ;------------------------------------------------------------------------
  710. ; CHECKVECTOR is called by REMOVE to compare the segment pointed to by an
  711. ; interrupt vector against a segment value supplied by the caller.
  712. ;   Entry:  AL - interrupt number
  713. ;   Exit:   ZF clear - segments do not match
  714. ;           ZF set   - segments match
  715. ;------------------------------------------------------------------------
  716. checkvector    proc    near
  717.         push    es
  718.         pop    cx
  719.         mov    ah,35h            ;get vector
  720.         int    21h
  721.         mov    ax,es            ;transfer segment to AX
  722.         cmp    ax,cx            ;compare
  723.         ret
  724. checkvector    endp
  725.  
  726. ;------------------------------------------------------------------------
  727. ; COPYSTR Copies an ASCIIZ string
  728. ;   Entry:  SI - Ptr to source ASCIIZ string
  729. ;           DI - Ptr to destination buffer
  730. ;------------------------------------------------------------------------
  731. copy_str    proc    near
  732.         push    ax
  733. copy_str_1:
  734.         lodsb
  735.         or    al,al
  736.         je    copy_str_2
  737.         stosb
  738.         jmp    short copy_str_1
  739. copy_str_2:
  740.         pop    ax 
  741.         ret
  742. copy_str        endp
  743.  
  744. code        ends
  745.         end    begin
  746. 
  747.